package com.zhdl.network.service.impl;

import cn.hutool.core.util.HexUtil;
import com.project.command.faq.event.behavior.BehaviorPerform;
import com.project.command.instruction.bo.SingleInstruction;
import com.project.common.util.ByteHelper;
import com.zhdl.common.util.IdUtil;
import com.zhdl.network.modbus.ModbusRtuRespPkg;
import com.zhdl.network.modbus.request.WriteSingleKeepRegisterReq;
import com.zhdl.network.motor.after.MotorAfterService;
import com.zhdl.network.service.MotorEasternService;
import com.zhdl.network.service.conf.PortConf;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;

import static com.project.command.instruction.strategy.abs.AbsDic.INSTRUCTION_DEFAULT_HEX;
import static com.zhdl.network.motor.analysis.MotorAnalysis.MOTOR_ANALYSIS;

@Slf4j
@Service
public class MotorEasternServiceImpl implements MotorEasternService {

    @Resource
    private BehaviorPerform behaviorPerform;

    @Resource
    private PortConf portConf;

    /**
     * 发送指令 - 接收指令
     */
    @Override
    public void sendDataPacket(String cmd) {
        SingleInstruction instruction = new SingleInstruction();
        instruction.setInstructionId(IdUtil.getUUID_8());

        //设置要发送的指令字符串
        //转换成十进制
        instruction.setInstruction(cmd);

        //INSTRUCTION_DEFAULT_HEX 原始字符串字符串
        //INSTRUCTION_DEFAULT 进行转码后发送执行
        instruction.setBeforeInstructionName(INSTRUCTION_DEFAULT_HEX);
        //默认使用com.zhdl.instruction.strategy包下后置策略
        instruction.setAfterInstructionName(MotorAfterService.MOTOR_AFTER_SERVICE);
        //客户端通信地址, 串口为数字, 网口为ip+端口       数据来源 : port_comm 或 port_socket 表
//        instruction.setPortKey("3");
        //东区的电机串口待定 -- 可能是3 测试的时候为了避免冲突 设为 1
        instruction.setPortKey(portConf.getComPortEast());
        //设置协议  数据来源 : protocols 表
        instruction.setProtocols(MOTOR_ANALYSIS);
        behaviorPerform.perform(instruction);
    }

    /**
     * 0x03 获取电机状态(包括Y轴与X轴)
     * 0x3200 状态字节显示驱动器的状态
     * 读取状态字，9437 表示原点找到
     * 01 03 32 00 00 01 8A B2
     *
     * @param slaveStationId 从站Id
     */
    @Override
    public String getMotorStatus(String slaveStationId) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3200");
        //设置 电机-寄存器个数
        req.setWriteValue("0001");
        try {
            //设置 电机-功能码 03 读单个寄存器
            byte[] bytes = ModbusRtuRespPkg.ReadSingleKeepRegister(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    /**
     * 0x06 写单个线圈寄存器 设置运动方式
     * 0x3100  控制字  先 F  后 1F   绝对位置运动时，上次目标位置到后，电机开始运动
     * 先 2F 后 3F   绝对位置运动时，电机立即开始运动
     * 01 06 31 00 00 2F C6 EA   01 06 31 00 00 3F C7 26
     *
     * @param slaveStationId 从站Id
     * @param motorRunType   运动方式
     */
    @Override
    public String setMotorRunType(String slaveStationId, String motorRunType) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3100");
        //设置 电机-运动方式
        req.setWriteValue(motorRunType);
        try {
            //设置 电机-功能码 06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    /**
     * 0x10 写多个线圈寄存器 设置梯形速度
     * 0x4A00  梯形速度    值200RPM (00 00 00 32) (50)
     * 01 10 4A 00 00 02 04 00 00 00 32 3D 19
     *
     * @param slaveStationId 从站Id
     * @param tSpeedValue    梯形速度
     */
    @Override
    public String setMotorRunTSpeed(String slaveStationId, Integer tSpeedValue) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("4A00");
        //设置 电机-梯形速度
        byte[] dataArray = ModbusRtuRespPkg.intToByte4(tSpeedValue);
        req.setWriteValue(ByteHelper.bytesArrayToHexString(dataArray));

        try {
            //设置 电机-功能码 10 写多个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteMoreKeepRegister(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return "";
    }

    /**
     * 0x10 写多个线圈寄存器 设置目标位置
     * 0x4000  目标位置    值50000DEC (C3 50 00 00)
     * 01 10 4A 00 00 02 04 00 00 00 32 3D 19
     *
     * @param slaveStationId   从站Id
     * @param destinationValue 脉冲数
     */
    @Override
    public String setMotorRunDistance(String slaveStationId, Integer destinationValue) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("4000");
        //设置 电机-梯形速度
        byte[] dataArray = ModbusRtuRespPkg.intToByte4(destinationValue);
        req.setWriteValue(ByteHelper.bytesArrayToHexString(dataArray));

        try {
            //设置 电机-功能码 10 写多个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteMoreKeepRegister(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return "";
    }

    /**
     * 东区电机-电机找原点_1
     */
    @Override
    public boolean motorGoHome_1(String slaveStationId) {
        /*
            1.设定工作模式为原点模式: 0x3500   0x6
            01 06 35 00 00 06 06 04
         */
        String motorWorkType = SetHomeWork("0x01");
        sendDataPacket(motorWorkType);

        /*
            2.寻找原点模式:0x4D00
            发送: 01 06 4D 00 00 14 9E A9
         */
        String motorHomeType = SetHomeType("0x01");
        sendDataPacket(motorHomeType);

        /*
            3.寻找转折信号时的速度
            发送: 01 10 50 10 00 02 04 00 00 00 32 8F 75
         */
        String motorTwistSpeed = setHomeTSpeed("0x01", 200);
        sendDataPacket(motorTwistSpeed);

        /*
            4.寻找原点时的速度:0x5020  150RPM
            发送:01 10 50 20 00 02 04 80 00 00 25 E5 AF
         */
        String motorHomeSpeed = setHomeSpeed("0x01", 150);
        sendDataPacket(motorHomeSpeed);

        /*
            5.设置控制字运动方式
            锁紧电机轴，电机开始运动  控制字0x3100  先0xF后0x1F
         */
        String motorHomeRunType = setHomeRunType("0x01", "0x0F");
        sendDataPacket(motorHomeRunType);

        String motorRunType = setMotorRunType("0x01", "0x1F");
        sendDataPacket(motorRunType);

        return true;
    }

    /**
     * 东区电机-电机找原点_2
     */
    @Override
    public boolean motorGoHome_2(String slaveStationId) {
        /*
            1.设定工作模式为原点模式: 0x3500   0x6
            01 06 35 00 00 06 06 04
         */
        String motorWorkType = SetHomeWork("0x01");
        sendDataPacket(motorWorkType);

        /*
            2.寻找原点模式:0x4D00
            发送: 01 06 4D 00 00 14 9E A9
         */
        String motorHomeType = SetHomeType("0x01");
        sendDataPacket(motorHomeType);

        /*
            3.寻找转折信号时的速度
            发送: 01 10 50 10 00 02 04 00 00 00 32 8F 75
         */
        String motorTwistSpeed = setHomeTSpeed("0x01", 200);
        sendDataPacket(motorTwistSpeed);

        /*
            4.寻找原点时的速度:0x5020  150RPM
            发送:01 10 50 20 00 02 04 80 00 00 25 E5 AF
         */
        String motorHomeSpeed = setHomeSpeed("0x01", 150);
        sendDataPacket(motorHomeSpeed);

        /*
            5.设置控制字运动方式
            锁紧电机轴，电机开始运动  控制字0x3100  先0xF后0x1F
         */
        String motorHomeRunType = setHomeRunType("0x01", "0x0F");
        sendDataPacket(motorHomeRunType);

        String motorRunType = setMotorRunType("0x01", "0x1F");
        sendDataPacket(motorRunType);

        return true;
    }


    /**
     * 东区电机-电机移动_1
     * 设置位置模式1,控制电机寻找目标位置
     *
     * @param slaveStationId   从站Id
     * @param destinationValue 脉冲数
     * @param tSpeedValue      梯形速度
     */
    @Override
    public boolean ctrlMotorMove_1(String slaveStationId, Integer destinationValue, Integer tSpeedValue) {
        /*
            1.设置位置模式
         */
        String motorRunWorkType = setRunWorkType(slaveStationId);
        sendDataPacket(motorRunWorkType);

        /*
            2.设置目标位置
         */
        String motorRunDistance = setMotorRunDistance(slaveStationId, destinationValue);
        sendDataPacket(motorRunDistance);

        /*
            3.设置梯形速度
            速度 RPM 需要转换为内部单位
            DEC=[(RPM*512*60000)/1875]
         */
        String motorRunTSpeed = setMotorRunTSpeed(slaveStationId, tSpeedValue);
        sendDataPacket(motorRunTSpeed);

        /*
            4.设置控制字运动方式
            先 2F 后 3F  绝对位置运动时,电机立即开始运动
            先 4F 后 5F  相对定位
         */
        String motorRunTypeBefore = setMotorRunType(slaveStationId, "0x2F");
        sendDataPacket(motorRunTypeBefore);

        String motorRunTypeAfter = setMotorRunType(slaveStationId, "0x3F");
        sendDataPacket(motorRunTypeAfter);

        return true;
    }

    /**
     * 东区电机-电机移动_2
     * 设置位置模式1,控制电机寻找目标位置
     *
     * @param slaveStationId   从站Id
     * @param destinationValue 脉冲数
     * @param tSpeedValue      梯形速度
     */
    @Override
    public boolean ctrlMotorMove_2(String slaveStationId, Integer destinationValue, Integer tSpeedValue) {
        /*
            1.设置位置模式
         */
        String motorRunWorkType = setRunWorkType(slaveStationId);
        sendDataPacket(motorRunWorkType);

        /*
            2.设置目标位置
         */
        String motorRunDistance = setMotorRunDistance(slaveStationId, destinationValue);
        sendDataPacket(motorRunDistance);

        /*
            3.设置梯形速度
            速度 RPM 需要转换为内部单位
            DEC=[(RPM*512*60000)/1875]
         */
        String motorRunTSpeed = setMotorRunTSpeed(slaveStationId, tSpeedValue);
        sendDataPacket(motorRunTSpeed);

        /*
            4.设置控制字运动方式
            先 2F 后 3F  绝对位置运动时,电机立即开始运动
            先 4F 后 5F  相对定位
         */
        String motorRunTypeBefore = setMotorRunType(slaveStationId, "0x2F");
        sendDataPacket(motorRunTypeBefore);

        String motorRunTypeAfter = setMotorRunType(slaveStationId, "0x3F");
        sendDataPacket(motorRunTypeAfter);

        return true;
    }

    /**
     * 东区电机-电机停止
     */
    @Override
    public boolean ctrlMotorStop() {
        String motorRunType = setMotorRunType("01", "0F");
        sendDataPacket(motorRunType);
        return true;
    }


    /**
     * 设定工作模式位原点模式
     *
     * @param slaveStationId 从站Id
     */
    public String SetHomeWork(String slaveStationId) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3500");
        //设置 电机-电机的工作模式
        req.setWriteValue("0006");
        try {
            //功能码06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    /**
     * 设定工作模式位原点模式
     *
     * @param slaveStationId 从站Id
     */
    public String SetHomeType(String slaveStationId) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("4D00");
        //设置 电机-电机的找远点模式
        req.setWriteValue("0018");

        try {
            //功能码06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    /**
     * 转折信号时的速度:0x5010 200RPM
     *
     * @param slaveStationId 从站Id
     * @param tSpeedValue    梯形速度
     */
    public String setHomeTSpeed(String slaveStationId, Integer tSpeedValue) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("5010");
        //设置 电机-找原点的速度 00000020
        req.setWriteValue(ByteHelper.byteToHexStr(tSpeedValue.byteValue()));

        try {
            //功能码 0x10 写多个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteMoreKeepRegister(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }

    /**
     * 原点时的速度:0x5020  150RPM
     *
     * @param slaveStationId 从站Id
     * @param tSpeedValue    梯形速度
     */
    public String setHomeSpeed(String slaveStationId, Integer tSpeedValue) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("5020");
        //设置 电机-找原点的速度 80000020
        req.setWriteValue(ByteHelper.byteToHexStr(tSpeedValue.byteValue()));

        try {
            //功能码 0x10 写多个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteMoreKeepRegister(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return "";
    }

    /**
     * 锁紧电机轴，电机开始运动 --- 电机找原点运动
     * 控制字0x3100  先0xF后0x1F
     *
     * @param slaveStationId 从站Id
     * @param motorRunType   电机运动类型
     */
    public String setHomeRunType(String slaveStationId, String motorRunType) {

        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3100");
        //设置 电机-运动方式
        req.setWriteValue(motorRunType);
        try {
            //设置 电机-功能码 06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return "";
    }


    /**
     * 锁紧电机轴，电机开始运动 ---- 电机运动
     * 控制字0x3500  先0xF后0x1F
     *
     * @param slaveStationId 从站Id
     */
    public String setRunWorkType(String slaveStationId) {
        WriteSingleKeepRegisterReq req = new WriteSingleKeepRegisterReq();
        //设置 电机-功能码Id
        req.setId(slaveStationId);
        //设置 电机-寄存器地址
        req.setStartAddr("3500");
        //设置 电机-运动方式
        req.setWriteValue("0001");
        try {
            //设置 电机-功能码 06 写单个寄存器
            byte[] bytes = ModbusRtuRespPkg.WriteSingleKeepRegister06(req);
            sendDataPacket(HexUtil.encodeHexStr(bytes));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        return "";
    }

}
